package org.example.spring.simple.framework.aop.intercept;

import org.example.spring.simple.framework.aop.aspect.ZJoinPoint;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 先进行判断，如果拦截器链为空，则说明目标方法无须增强，直接调用目标方法并返回。
 * 如果拦截器链不为空，则将拦截器链中的方法按顺序执行，直到拦截器链中所有方法全部执行完毕。
 */
public class ZMethodInvocation implements ZJoinPoint {
    //代理对象
    private Object proxy;
    //代理目标
    private Object target;
    //代理方法
    private Method method;
    //代理类
    private Class<?> targetClass;
    //代理方法的实参列表
    private Object[] arguments;
    //回调方法链
    private List interceptorsAndDynamicMethodMatchers;
    //保存自定义属性
    private Map<String, Object> userAttributes;
    //定义一个索引，从-1开始来记录当前拦截器执行的位置
    private int currentInterceptorIndex = -1;

    public ZMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class<?> targetClass,
                             List interceptorsAndDynamicMethodMatchers) {
        this.proxy = proxy;
        this.method = method;
        this.target = target;
        this.targetClass = targetClass;
        this.arguments = arguments;
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }

    @Override
    public Object getThis() {
        return this.target;
    }

    @Override
    public Object[] getArguments() {
        return this.arguments;
    }

    @Override
    public Method getMethod() {
        return this.method;
    }

    @Override
    public void setUserAttribute(String key, Object value) {
        if (value != null) {
            if (this.userAttributes != null) {
                this.userAttributes = new HashMap<>();
            }
            this.userAttributes.put(key, value);
        } else {
            if (this.userAttributes != null) {
                this.userAttributes.remove(key);
            }
        }
    }

    @Override
    public Object getUserAttribute(String key) {
        return (this.userAttributes != null ? this.userAttributes.get(key) : null);
    }

    /**
     * 先进行判断，如果拦截器链为空，则说明目 标方法无须增强，直接调用目标方法并返回。
     * 如果拦截器链不为空，则 将拦截器链中的方法按顺序执行，直到拦截器链中所有方法全部执行完毕。
     * @return
     * @throws Throwable
     */
    public Object proceed() throws Throwable {
        //如果Interceptor执行完了，则执行joinPoint
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.method.invoke(this.target, this.arguments);
        }
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++currentInterceptorIndex);
        //动态匹配joinPoint
        if (interceptorOrInterceptionAdvice instanceof ZMethodInterceptor) {
            ZMethodInterceptor interceptor = (ZMethodInterceptor) interceptorOrInterceptionAdvice;
            return interceptor.invoke(this);
        } else {
            //继续执行当前拦截器
            return proceed();
        }
    }
}
